#define __QYQ_TRILED_DRIVE_C_
#include "qyq_triled_drive.h"
#include <math.h>  

volatile static uint8_t triled_number = 0; // TRILED数量
volatile static qyq_triled_control_block_t* triled_list = NULL;

#define LED_HIGH 0xFFFF
#define LED_LOW 0x0000
#define PIN_NUM 10
#define LED_NUMBER 64 * 24

uint8_t  triled_drive[][8] = {
   {56,55,40,39,24,23,8,7},
   {57,54,41,38,25,22,9,6},
   {58,53,42,37,26,21,10,5},
   {59,52,43,36,27,20,11,4},
   {60,51,44,35,28,19,12,3},
   {61,50,45,34,29,18,13,2},
   {62,49,46,33,30,17,14,1},
   {63,48,47,32,31,16,15,0},
};

// #define LED_NUMBER 4

// 用于传输的数据结构体
struct bflb_device_s* wo;
struct bflb_device_s* dma0_ch0;
struct bflb_dma_channel_lli_transfer_s tx_transfers[1];
struct bflb_dma_channel_lli_pool_s tx_llipool[2];
static ATTR_NOCACHE_NOINIT_RAM_SECTION uint16_t tx_buffer[LED_NUMBER];

void dma0_ch0_isr(void* arg)
{
    // printf("tc done\r\n");
}

static void qyq_triled_sram_init(void)
{
    for (uint32_t i = 0; i < LED_NUMBER; i++)
    {
        tx_buffer[i] = LED_HIGH;
    }
}

static void qyq_bl618_wo_init(void)
{
    static struct bflb_wo_cfg_s cfg = {
        .code_total_cnt = 44,
        .code0_first_cnt = 12,
        .code1_first_cnt = 32,
        .code0_first_level = 1,
        .code1_first_level = 1,
        .idle_level = 0,
        .fifo_threshold = 64,
        .mode = WO_MODE_WRITE,
    };

    static struct bflb_dma_channel_config_s dma_cfg = {
        .direction = DMA_MEMORY_TO_PERIPH,
        .src_req = DMA_REQUEST_NONE,
        .dst_req = DMA_REQUEST_WO,
        .src_addr_inc = DMA_ADDR_INCREMENT_ENABLE,
        .dst_addr_inc = DMA_ADDR_INCREMENT_DISABLE,
        .src_burst_count = DMA_BURST_INCR8,
        .dst_burst_count = DMA_BURST_INCR8,
        .src_width = DMA_DATA_WIDTH_16BIT,
        .dst_width = DMA_DATA_WIDTH_16BIT,
    };

    wo = bflb_device_get_by_name("wo");
    bflb_wo_init(wo, &cfg);
    bflb_wo_pin_init(wo, PIN_NUM, WO_MODE_WRITE);
    bflb_wo_enable_dma(wo);

    dma0_ch0 = bflb_device_get_by_name("dma0_ch0");
    bflb_dma_channel_init(dma0_ch0, &dma_cfg);
    bflb_dma_channel_tcint_mask(dma0_ch0, 0);
    bflb_dma_channel_irq_attach(dma0_ch0, dma0_ch0_isr, NULL);

    tx_transfers[0].src_addr = (uint32_t)tx_buffer;
    tx_transfers[0].dst_addr = DMA_ADDR_WO_TDR;
    tx_transfers[0].nbytes = LED_NUMBER * sizeof(uint16_t);
    // tx_transfers[0].nbytes = 24 * 2 * 5;
}

// 把红绿蓝转换成数组
static void qyq_triled_set_send_buf(uint32_t led_id, uint8_t red, uint8_t green, uint8_t blue)
{
    for (uint32_t i = 0; i < 24; i++)
    {
        if (i < 8)
        {
            if (green & (0x80 >> i))
            {
                tx_buffer[led_id * 24 + i] = LED_HIGH;
            }
            else
            {
                tx_buffer[led_id * 24 + i] = LED_LOW;
            }
        }
        else if (i < 16)
        {
            if (red & (0x80 >> (i - 8)))
            {
                tx_buffer[led_id * 24 + i] = LED_HIGH;
            }
            else
            {
                tx_buffer[led_id * 24 + i] = LED_LOW;
            }
        }
        else
        {
            if (blue & (0x80 >> (i - 16)))
            {
                tx_buffer[led_id * 24 + i] = LED_HIGH;
            }
            else
            {
                tx_buffer[led_id * 24 + i] = LED_LOW;
            }
        }
    }
}

// 数据转换
static void qyq_triled_start(void)
{
    for (uint32_t i = 0; i < triled_number; i++)
    {
        if (triled_list[i].status == 1)
        {
            qyq_triled_set_send_buf(i, triled_list[i].red, triled_list[i].green, triled_list[i].blue);
        }
        else
        {
            qyq_triled_set_send_buf(i, 0, 0, 0);
        }
    }
    bflb_dma_channel_stop(dma0_ch0);
    bflb_l1c_dcache_clean_invalidate_range(tx_buffer, sizeof(tx_buffer));
    bflb_dma_channel_lli_reload(dma0_ch0, tx_llipool, 2, tx_transfers, 1);
    bflb_dma_channel_start(dma0_ch0);
    vTaskDelay(pdMS_TO_TICKS(5));
}

/**
 * @brief 初始化TRILED驱动
 * @param triledlist 指向TRITRILED控制块数组的指针，用于存储多个TRILED的配置信息
 * @param trilednumber 需要初始化的TRILED数量
 * @return int8_t 返回状态码，0表示成功，非0表示失败
 */
int8_t qyq_triled_drive_init(qyq_triled_control_block_t* triledlist, uint8_t trilednumber)
{
    if (triledlist == NULL)
    {
        return -2;
    }

    triled_number = trilednumber;
    triled_list = triledlist;

    for (uint32_t i = 0; i < trilednumber; i++)
    {
        triled_list[i].status = 0;
        triled_list[i].red = 0;
        triled_list[i].green = 0;
        triled_list[i].blue = 0;
    }

    // LED数据初始化
    qyq_triled_sram_init();

    // SPI初始化
    qyq_bl618_wo_init();

    // 执行初始化
    qyq_triled_start();

    return 0;
}

/**
 * @brief 打开指定的TRILED
 * @param triled_id 需要打开的TRILED的ID
 * @return int8_t 返回状态码，0表示成功，非0表示失败
 */
int8_t qyq_triled_drive_turn_on(uint8_t triled_id)
{
    if (triled_id >= triled_number)
    {
        return -1;
    }

    if (triled_list == NULL)
    {
        return -2;
    }

    triled_list[triled_id].status = 1;
    qyq_triled_start();

    return 0;
}

/**
 * @brief 打开所有的TRILED
 * @return int8_t 返回状态码，0表示成功，非0表示失败
 */
int8_t qyq_triled_drive_turn_onall(void)
{
    uint8_t i = 0;
    for (i = 0; i < triled_number; i++)
    {
        triled_list[i].status = 1;
    }
    qyq_triled_start();
    return 0;
}

/**
 * @brief 关闭指定的TRILED
 * @param triled_id 需要关闭的TRILED的ID
 * @return int8_t 返回状态码，0表示成功，非0表示失败
 */
int8_t qyq_triled_drive_turn_off(uint8_t triled_id)
{
    if (triled_id >= triled_number)
    {
        return -1;
    }

    if (triled_list == NULL)
    {
        return -2;
    }

    triled_list[triled_id].status = 0;

    qyq_triled_start();

    return 0;
}

/**
 * @brief 关闭所有的TRILED
 * @return int8_t 返回状态码，0表示成功，非0表示失败
 */
int8_t qyq_triled_drive_turn_offall(void)
{
    uint8_t i = 0;
    for (i = 0; i < triled_number; i++)
    {
        triled_list[i].status = 0;
    }
    qyq_triled_start();
    return 0;
}

/**
 * @brief 切换指定的TRILED状态（打开->关闭或关闭->打开）
 * @param triled_id 需要切换状态的TRILED的ID
 * @return int8_t 返回状态码，0表示成功，非0表示失败
 */
int8_t qyq_triled_drive_toggle(uint8_t triled_id)
{
    if (triled_id >= triled_number)
    {
        return -1;
    }

    if (triled_list == NULL)
    {
        return -2;
    }

    if (triled_list[triled_id].status == 0)
    {
        triled_list[triled_id].status = 1;
    }
    else
    {
        triled_list[triled_id].status = 0;
    }

    qyq_triled_start();

    return 0;
}

/**
 * @brief 获取指定TRILED的当前状态
 * @param triled_id 需要查询的TRILED的ID
 * @return int8_t 返回TRILED的当前状态，1表示打开，0表示关闭，负数表示错误
 */
int8_t qyq_triled_drive_get_state(uint8_t triled_id, qyq_triled_control_block_t* triledstatus)
{
    if (triled_id >= triled_number)
    {
        return -1;
    }

    if (triledstatus == NULL)
    {
        return -1;
    }

    if (triled_list == NULL)
    {
        return -2;
    }

    triledstatus->status = triled_list[triled_id].status;
    triledstatus->red = triled_list[triled_id].red;
    triledstatus->green = triled_list[triled_id].green;
    triledstatus->blue = triled_list[triled_id].blue;

    return 0;
}

/**
 * @brief 设置指定TRILED的颜色
 * @param triled_id 需要设置颜色的TRILED的ID
 * @param red 红色分量值（0-255）
 * @param green 绿色分量值（0-255）
 * @param blue 蓝色分量值（0-255）
 * @return int8_t 返回状态码，0表示成功，非0表示失败
 */
int8_t qyq_triled_drive_set_color(uint8_t triled_id, uint8_t red, uint8_t green, uint8_t blue)
{
    if (triled_id >= triled_number)
    {
        return -1;
    }

    if (triled_list == NULL)
    {
        return -2;
    }

    triled_list[triled_id].red = red;
    triled_list[triled_id].green = green;
    triled_list[triled_id].blue = blue;

    qyq_triled_start();

    return 0;
}

/**
 * @brief 设置所有TRILED的颜色
 * @param triled_id 需要设置颜色的TRILED的ID
 * @param red 红色分量值（0-255）
 * @param green 绿色分量值（0-255）
 * @param blue 蓝色分量值（0-255）
 * @return int8_t 返回状态码，0表示成功，非0表示失败
 */
int8_t qyq_triled_drive_set_allcolor(uint8_t red, uint8_t green, uint8_t blue)
{
    if (triled_list == NULL)
    {
        return -2;
    }

    for (uint32_t i = 0; i < triled_number; i++)
    {
        triled_list[i].red = red;
        triled_list[i].green = green;
        triled_list[i].blue = blue;
    }

    qyq_triled_start();

    return 0;
}

/**
 * @brief 熄灭TRILED之后剩余灯珠
 * @param triled_id 需要设置颜色的TRILED的ID
 * @return int8_t 返回状态码，0表示成功，非0表示失败
 */

int8_t qyq_triled_drive_set_othercolor(uint8_t triled_id)
{
    if (triled_list == NULL)
    {
        return -2;
    }

    for (uint32_t i = triled_id; i < triled_number; i++)
    {
        triled_list[i].red = 0;
        triled_list[i].green = 0;
        triled_list[i].blue = 0;
    }

    qyq_triled_start();

    return 0;
}


int8_t triled_drive_set_color_arry(uint8_t* triled_ids, uint8_t leds_numble, uint8_t red, uint8_t green, uint8_t blue)
{
    if (triled_ids==NULL) {
        return -1;
    }
    for (size_t i = 0; i < leds_numble; i++)
    {
        if (triled_ids[i]>= triled_number)
        {
            return -1;
        }
    }
    for (size_t i = 0; i < leds_numble; i++)
    {
        triled_list[triled_ids[i]].red = red;
        triled_list[triled_ids[i]].green = green;
        triled_list[triled_ids[i]].blue = blue;

    }
    qyq_triled_start();

    return 0;
}

int8_t triled_drive_set_color_arry_no_start(uint8_t* triled_ids, uint8_t leds_numble, uint8_t red, uint8_t green, uint8_t blue)
{
    if (triled_ids==NULL) {
        return -1;
    }
    for (size_t i = 0; i < leds_numble; i++)
    {
        if (triled_ids[i]>= triled_number)
        {
            return -1;
        }
    }
    for (size_t i = 0; i < leds_numble; i++)
    {
        triled_list[triled_ids[i]].red = red;
        triled_list[triled_ids[i]].green = green;
        triled_list[triled_ids[i]].blue = blue;
        triled_list[triled_ids[i]].status = 1;
    }
    return 0;
}

void  triled_drive_set_color_start(void)
{
    for (size_t i = 0; i < triled_number; i++)
    {
        if (!triled_list[i].status) {
            triled_list[i].red = 0;
            triled_list[i].green = 0;
            triled_list[i].blue = 0;
        }
    }
    qyq_triled_start();
}


void  triled_drive_set_color_stop(void)
{
    for (size_t i = 0; i < triled_number; i++)
    {
        triled_list[i].status = 0;
    }
    qyq_triled_start();
}

uint8_t triled_drive_get_status_all(void)
{
    for (size_t i = 0; i < triled_number; i++)
    {
        if (triled_list[i].status==1)
            return 0;
    }
    return 1;
}